package com.sky.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.sky.constant.MessageQueueTopicConstant;
import com.sky.constant.RedisConstant;
import com.sky.context.BaseContext;
import com.sky.entity.VoucherOrder;
import com.sky.mapper.VoucherOrderMapper;
import com.sky.service.VoucherOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;

/**
 * @Author: invictusQAQ
 * @Date: 2023-09-08-9:28
 * @Description:
 */
@Service
@Slf4j
public class VoucherOrderImpl implements VoucherOrderService {

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private VoucherOrderMapper voucherOrderMapper;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;

    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }

    /**
     * 秒杀券下单
     * @param voucherId
     * @return Long
     **/
    public Long submitOrder(Long voucherId) {
        if(judgeVoucherOrder(voucherId)>0){
            return judgeVoucherOrder(voucherId);
        }

        Long userId= BaseContext.getCurrentId();
        Snowflake snowflake=IdUtil.getSnowflake(1,1);
        Long voucherOrderId= snowflake.nextId();
        VoucherOrder voucherOrder=VoucherOrder.builder()
                .id(voucherOrderId)
                .voucherId(voucherId)
                .userId(userId)
                .build();
        rocketMQTemplate.asyncSend(MessageQueueTopicConstant.SECKILL_VOUCHER_TOPIC+":"+MessageQueueTopicConstant.SECKILL_VOUCHER_TAG,
                JSON.toJSONString(voucherOrder), new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        log.info("秒杀券下单消息发送成功:"+sendResult.getMsgId());
                    }

                    @Override
                    public void onException(Throwable e) {
                        log.info(e.getMessage());
                    }
                });
        return voucherId;
    }

    /**
     * 判断秒杀券购买资格
     * @param voucherId
     * @return void
     **/
    private Long judgeVoucherOrder(Long voucherId){
        //0代表有购买资格，1代表秒杀券已售罄，2代表重复下单
        Long userId= BaseContext.getCurrentId();
        // 创建锁对象
        RLock lock= redissonClient.getLock(RedisConstant.LOCK_ORDER_KEY+userId);
        //获取锁
        boolean isLock=lock.tryLock();
        // 判断是否获取锁成功
        if(!isLock){
            // 获取锁失败，返回错误或重试
            log.error("不允许重复下单");
            return 2L;
        }
        //基于lua判断一人一单和库存超卖
        try{
            Long result=stringRedisTemplate.execute(SECKILL_SCRIPT, Collections.emptyList(),voucherId.toString(),userId.toString());
            int r=result.intValue();
            if (r != 0) {
                //不为0 ，代表没有购买资格
                log.info(r == 1 ? "秒杀券已售罄" : "不允许重复下单");
                return Long.valueOf(r);
            }
        }finally {
            lock.unlock();
        }
        return 0L;
    }
}
